package log

import "strings"

type Level uint
type Levels = Level

const NOLOG Level = 0
const (
	FATAL Level = 1 << iota
	ERROR
	WARN
	INFO
	DEBUG
)

const (
	Lv_Fatal Levels = FATAL
	Lv_Error        = Lv_Fatal | ERROR
	Lv_Warn         = Lv_Error | WARN
	Lv_Info         = Lv_Warn | INFO
	Lv_Debug        = Lv_Info | DEBUG
)

type Str2Level func(string) Level
type Level2Str func(Level) string

var (
	s2Level Str2Level
	lv2str  Level2Str
)

func init() {
	s2Level = ParseLevel
	lv2str = LevelString
}

func ParseLevel(lv string) Level {
	s := strings.ToLower(lv)
	switch s {
	case "debug":
		return DEBUG
	case "info":
		return INFO
	case "warn", "warning":
		return WARN
	case "error":
		return ERROR
	case "fatal":
		return FATAL
	}
	switch s[:5] {
	case "fatal":
		return FATAL
	case "error":
		return ERROR
	case "debug":
		return DEBUG
	}
	switch s[:4] {
	case "info":
		return INFO
	case "warn":
		return WARN
	}
	return NOLOG
}

func SetLevelParse(f Str2Level) {
	if f != nil {
		s2Level = f
	}
}

func LevelString(lv Level) string {
	switch lv {
	case DEBUG, Lv_Debug:
		return "DEBUG"
	case INFO, Lv_Info:
		return "INFO"
	case WARN, Lv_Warn:
		return "WARN"
	case ERROR, Lv_Error:
		return "ERROR"
	case FATAL:
		return "FATAL"
	default:
		l := FATAL
		for l <= DEBUG {
			if lv.Enable(l) {
				return lv2str(l)
			}
			l = l << 1
		}
	}
	return "UNKNOWN"
}

func SetLevelName(f Level2Str) {
	if f != nil {
		lv2str = f
	}
}

func NewLevel(ct string) Levels {
	var lv Levels
	ct = strings.ReplaceAll(ct, " ", "") //去除空格
	cts := strings.Split(ct, "|")
	if len(cts) > 1 {
		for _, s := range cts {
			lv |= s2Level(s)
		}
	} else {
		lv = s2Level(ct)
		switch lv {
		case ERROR:
			lv = Lv_Error
		case WARN:
			lv = Lv_Warn
		case INFO:
			lv = Lv_Info
		case DEBUG:
			lv = Lv_Debug
		}
	}
	return lv
}

func (x Level) String() string {
	return lv2str(x)
}

func (x Levels) Enable(lv Level) bool {
	return (x & lv) != 0
}
